package main;

import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.Renderer.VertexLabel.Position;
import graphNew.AgentEdge;
import graphNew.DinicMainGraph;
import graphNew.MainGraph;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;



import java.awt.Color;
import java.awt.Dimension;
import java.awt.Paint;
import java.util.Vector;

import javax.swing.JFrame;

import org.apache.commons.collections15.Transformer;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;

import clustering.ClusterAlgo;
import clustering.VerticesSet;
import components.Agent;
import components.Goal;
import components.Operator;
import components.Variable;



public class Main {
	
	public static final String INPUT = "test input";
	public static final String OUTPUT = "output";
	public static final int NUM_OF_CANDIDATES = 4;
	public static final int NUM_OF_CLUSTERS = 4;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ProgramOptions.inputFile = "";
		ProgramOptions.outputFile = "";
		processClustering();

	}
			
	//MAIN CLUSTERING FUNCTION
	//gets input from the input file, reads and parses it, generates the graph, calls voltage cluster algorithm,
	//produces agents graph, and output file
	public static void processClustering(){
		String fullInputFilePath = ProgramOptions.inputFile;
		String fullOutputFilePath = ProgramOptions.outputFile;
		Vector<Variable> vars = new Vector<Variable>();
		Vector<Goal> goals = new Vector<Goal>();
		Vector<Operator> operators = new Vector<Operator>();
		
		try {
			io.IoHandler.ParseFile(fullInputFilePath, vars, goals, operators);
			MainGraph mainGraph = new MainGraph(operators);
			mainGraph.printMainGraph();
			generateClusters(mainGraph);
			io.IoHandler.outputToFile(fullOutputFilePath, fullInputFilePath, vars, goals, operators);
		}
		catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//processes the Edge Betweenness clustering option of the aplication.
	public static void processEBclustering(){
		String fullInputFilePath = ProgramOptions.inputFile;
		String fullOutputFilePath = ProgramOptions.outputFile;
		Vector<Variable> vars = new Vector<Variable>();
		Vector<Goal> goals = new Vector<Goal>();
		Vector<Operator> operators = new Vector<Operator>();
		
		try {
			io.IoHandler.ParseFile(fullInputFilePath, vars, goals, operators);
			MainGraph mainGraph = new MainGraph(operators);
			mainGraph.printMainGraph();
			generateEBclusters(mainGraph);
			io.IoHandler.outputToFile(fullOutputFilePath, fullInputFilePath, vars, goals, operators);
		}
		catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	
	
	//generates and visualizes the voltage clustering algorithm
	public static void generateClusters(MainGraph graph){
		ClusterAlgo clusterAlgo = new ClusterAlgo(ProgramOptions.numberOfAgents);
		clusterAlgo.cluster(graph);
		clusterAlgo.showClusterAgentsGraph();			

	}
	
	//generates and visualizes the edge betwenness clustering algorithm
	public static void generateEBclusters(MainGraph graph){
		int numEdgesToRemove;
		try {
			numEdgesToRemove = (graph.getMainGraph().edgeSet().size()) / 2;
		} catch (Exception e) {
			numEdgesToRemove = 1;
			e.printStackTrace();
		}
		ProgramOptions.edgesToRemove = numEdgesToRemove;
		ClusterAlgo clusterAlgo = new ClusterAlgo(0);	//the param doesn't matter
		clusterAlgo.edgeBetwennesCluster(graph);
		clusterAlgo.showClusterAgentsGraph();			

	}
	
	
	//produces and returns a graph out of vertices set (each vertex is an operator of the problem)
	public static MainGraph getGraphFromVerticesSet(VerticesSet vSet){
		Vector<Operator> operators = new Vector<Operator> ();
		for(Operator op : vSet.getNodesSet()){
			operators.add(op);
		}		
		return new MainGraph(operators);
	}
	
	
	//Visualizing the agent graph, using JUNG.
	public static void paintAgentGraph(DefaultDirectedWeightedGraph<Agent, AgentEdge> graph){
		Graph jungGraph = Translating.agentGraphToJungGraph(graph);
		
		// The Layout<V, E> is parameterized by the vertex and edge types
		Layout<Agent, DefaultWeightedEdge> layout = new FRLayout<Agent, DefaultWeightedEdge>(jungGraph);
		layout.setSize(new Dimension(500,500)); // sets the initial size of the space
		
		// The BasicVisualizationServer<V,E> is parameterized by the edge types
		VisualizationViewer<Agent,DefaultWeightedEdge> vv =
		new VisualizationViewer<Agent,DefaultWeightedEdge>(layout);
		vv.setPreferredSize(new Dimension(600,600)); //Sets the viewing area size
		
		//transformer design pattern for painting sink / source differently
		Transformer<Agent,Paint> vertexPaint = new Transformer<Agent,Paint>() {
			public Paint transform(Agent a) {
				return Color.CYAN;
			}
		};
		
		//Vertices and edges view editing
		vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
		vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Agent>());
		vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<DefaultWeightedEdge>());
		vv.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);
		
		DefaultModalGraphMouse x= new DefaultModalGraphMouse();
		//iterative mouse for ZOOM IN/OUT
		DefaultModalGraphMouse<Agent,DefaultWeightedEdge> gm = 
			new DefaultModalGraphMouse<Agent,DefaultWeightedEdge>();
		gm.setMode(ModalGraphMouse.Mode.TRANSFORMING);
		vv.setGraphMouse(gm);
		
		//graphic output / visualization
		JFrame frame = new JFrame("Agents Graph");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(vv);
		frame.pack();
		frame.setVisible(true);
		
	}
	
	
	
	/*public static MainGraph generateTestGraph(Vector<components.Variable> vars, Vector<components.Goal> mainGoals, Vector<Operator> operators){
						
		try {
			io.IoHandler.ParseFile(INPUT, vars, mainGoals, operators);
		} catch (Exception e) {
			e.printStackTrace();
		}			
				
		MainGraph g = new MainGraph(operators);
		return g;
	}*/

	
	/*public static DinicMainGraph generateFlowNetworkGraph(MainGraph graph, Vector<Goal> goals){
		try {
			return new DinicMainGraph(goals, graph);			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}*/
}
